package taskprocess

import (
	"acs/comet/client"
	"acs/comet/proto"
	"acs/comet/config"
	"time"
	"sync"
	"acs/pbmodel"
	"strings"
)

// HandleEvent 保存event信息，并根据event信息向在线客户端推送消息。
func HandleEvent(task *EventTask) (err error) {

	//如果uid列表是空的就直接返回
	if len(task.TargetUID) == 0 {
		return
	}

	wg := sync.WaitGroup{}
	taskLock := &sync.Mutex{}
	var readyIds []string

	upFn := func(c *client.Client, taskI interface{}) {
		wg.Add(1)
		defer func() {
			wg.Done()
		}()

		task := taskI.(*EventTask)
		regInfo := c.GetRegisterInfo()

		//根据过滤条件判断当前用户是否是需要发送的用户
		if !filterUser(task, regInfo) {
			return
		}

		logger.Debugf("Sending event task to user[%v]: %+v", regInfo.UID, proto.CmdEvent)
		eventResp := c.SendCmd(proto.CmdEvent, &task.Event, &pbmodel.EventResp{})

		//如果出现错误那么user_task 状态不变, 如果全部成功那么就修改状态为已发送
		if eventResp.Err != nil {
			logger.Warnf("Event failed to [%v]: %v", c.GetRemoteAddr(), eventResp.Err)
			return
		}
		respData := eventResp.RespData.(*pbmodel.EventResp)
		if *respData.Status != 6000 {
			logger.Warnf("Client[%v] event failed: %v:%v", c.GetRemoteAddr(), respData.Status)
			return
		}

		//执行完后将执行的uid放到slice中
		taskLock.Lock()
		readyIds = append(readyIds, *regInfo.UID)
		taskLock.Unlock()


	}
	clients.MapFunc(upFn, task)
	wg.Wait()
	//status 发送状态 0 发送未成功，1 发送成功, 同时allSend 1 表示全部发送,0 消息是部分发送
	var allSend int
	if strings.Trim(task.TargetUID[0], " ") == "*" {
		allSend = 1
		readyIds = append(readyIds, "*") //添加一个*的用户任务用来保存条件
	}else {
		//如果不是全局消息，那么存的是失败列表(包括发送失败的和过滤失败的，因为现在过滤失败但是有可能下次连得时候符合，那么也需要发送。)
		readyIds = SliceRemove(task.TargetUID, readyIds)
	}

	//只有有uid存在的时候才进行存储
	if len(task.TargetUID) > 0 {
		//构建存储对象
		eventTaskToStore := EventTaskToStore{}
		eventTaskToStore.Label = task.Label
		eventTaskToStore.Content = task.Content
		eventTaskToStore.Expiration = time.Now().Add(time.Duration(config.Conf.EventExpiration)*time.Second).Unix()
		eventTaskToStore.AllSend = allSend

		//存入mongodb中，*已发送列表 status=1  uid未发送列表 status=0 
		err = StoreEventTaskToDb(&eventTaskToStore, task, readyIds, allSend)
		if err != nil {
			logger.Warnf("Failed to handle event task. ERR: %v", err)
			return
		}
	}

	return
}

//删除指定items,并且可以删除重复id
func SliceRemove(slice []string, remove []string) (result []string)  {

	m := make(map[string]bool)
	for _, v := range remove  {
		v = strings.Trim(v, " ")
		m[v] = true
	}

	for _, val := range slice  {
		val = strings.Trim(val, " ")
		if _, ok := m[val]; !ok {
			result = append(result, val)
		}
	}
	return
}

func filterUser(task *EventTask, regInfo pbmodel.RegisterInfo) (isTarget bool)  {


	//状态是否发送
	var isTargetClient bool
	//如果第一个是*
	headUid := strings.Trim(task.TargetUID[0], " ")
	if headUid != "*" {
		for _, uid := range task.TargetUID {
			if strings.Trim(uid, " ") == *regInfo.UID {
				isTargetClient = true
				break
			}
		}
	}else {
		isTargetClient = true
	}

	if !isTargetClient {
		return
	}


	//appver start  *就不进行过滤了
	if task.Appver[0] != "*" && VersionOrdinal(task.Appver[0]) > VersionOrdinal(*regInfo.Appver) {
		return
	}
	//appver end
	if task.Appver[1] != "*" && VersionOrdinal(task.Appver[1]) < VersionOrdinal(*regInfo.Appver){
		return
	}

	//bundleid 等于0的情况为没有过滤条件
	if len(task.BundleIds) > 0 {
		if ok, _ :=  InArrayString(*regInfo.BundleID, task.BundleIds); !ok {
			return
		}
	}

	//system
	if len(task.System) > 0 {
		if ok, _ := InArrayInt(int(*regInfo.System), task.System); !ok {
			return
		}
	}

	//osversion start
	if task.OSVersion[0] != "*" && VersionOrdinal(task.OSVersion[0]) > VersionOrdinal(*regInfo.OSVersion) {
		return
	}
	//osversion end
	if task.OSVersion[1] != "*" && VersionOrdinal(task.OSVersion[1]) < VersionOrdinal(*regInfo.OSVersion){
		return
	}

	//brand
	if len(task.Brand) > 0 {
		if ok, _ := InArrayString(*regInfo.Brand, task.Brand); !ok {
			return
		}
	}

	//model
	if len(task.Model) > 0 {
		if ok, _ := InArrayString(*regInfo.Model, task.Model); !ok {
			return
		}
	}

	isTarget= true

	return
}



/**
字符串是否在slice中
如果在exists返回true, index返回第几个元素
 */
func InArrayString(val string, array []string) (exists bool, index int) {
	exists = false
	index = -1;

	for i, v := range array {
		if val == v {
			index = i
			exists = true
			return
		}
	}

	return
}

/**
数字是否在slice中
如果在exists返回true, index返回第几个元素
 */
func InArrayInt(val int, array []int) (exists bool, index int) {
	exists = false
	index = -1;

	for i, v := range array {
		if val == v {
			index = i
			exists = true
			return
		}
	}

	return
}
/**
将版本号字符串进行转换，然后就可以根据字符串直接判断大小

 */
func VersionOrdinal(version string) string {
	// ISO/IEC 14651:2011
	const maxByte = 1<<8 - 1
	vo := make([]byte, 0, len(version)+8)
	j := -1
	for i := 0; i < len(version); i++ {
		b := version[i]
		if '0' > b || b > '9' {
			vo = append(vo, b)
			j = -1
			continue
		}
		if j == -1 {
			vo = append(vo, 0x00)
			j = len(vo) - 1
		}
		if vo[j] == 1 && vo[j+1] == '0' {
			vo[j+1] = b
			continue
		}
		if vo[j]+1 > maxByte {
			panic("VersionOrdinal: invalid version")
		}
		vo = append(vo, b)
		vo[j]++
	}
	return string(vo)
}